/* 
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

/********************* OBJECT DEFINITION *********************/

/**
 * brObject class definition
 * @param {brPoint} startPoint
 * @returns {brObject}
 */

var slideWidth = 1366;
function brObject(startPoint, width, height, speed, maxSpeed, accelerator, effects, style) {
    this.type = '';
    this.index = 0;
    this.position = startPoint;
    if (startPoint != undefined) {
        this.drawPosition = new brPoint(startPoint.x, startPoint.y);
        this.startPosition = new brPoint(startPoint.x, startPoint.y);
        this.animateTo = new brPoint(startPoint.x, startPoint.y);
    }
    //this.orgPos = new brPoint(startPoint.x, startPoint.y);
    this.width = width;
    this.drawWidth = width;
    this.height = height;
    this.drawHeight = height;
    this.speed = speed;
    this.maxSpeed = maxSpeed;
    this.accelerator = accelerator;
    this.style = style;
    var styles = {};
    for (var key in style) {
        styles[key] = '' + style[key];
    }
    this.orgStyle = styles;
    this.effects = effects;
    this.prev = null;
    this.next = null;
    this.mouseDown = objectMouseDown;
    this.mouseMove = objectMouseMove;
    this.selectionEnd = objectSelectionEnd;
    this.selectable = true;
    this.selecting = false;
    this.resizable = true;
    this.animated = false;
}

function objectMouseDown() {
    objBoundary.visible = true;
    selection.selecting = true;
    switch (this.type) {
        case "Text":
            $('#text-editor').val(selection.content);
            var fontSize = parseFloat(selection.style.fontSize) * slideWidth / myCanvas.width + 'px';
            var fontStyle = selection.style.fontStyle;
            var fontColor = selection.style.fontColor;

            $('.text-editor-control li.font-size ul li').each(function() {
                if ($(this).attr('value') == fontSize)
                    $(this).addClass('selected');
                else
                    $(this).removeClass('selected');
            });

            $('.text-editor-control li.font-weight ul li').each(function() {
                if (fontStyle.indexOf($(this).attr('value')) !== -1)
                    $(this).addClass('selected');
                else
                    $(this).removeClass('selected');
            });

            $('.text-editor-control li.font-color ul li').each(function() {
                if ($(this).attr('value') == fontColor)
                    $(this).addClass('selected');
                else
                    $(this).removeClass('selected');
            });
            
            $('#text-editor').hide();
            $('.text-editor-control').show();
            break;
        case "Rectangle":
        case "Elipse":
            $('.object-format li.border-color ul li').each(function() {

            });
            $('.object-format li.backgorund-color ul li').each(function() {

            });
            $('.object-format').show();
            break;
    }
}

function objectMouseMove() {

}

function objectSelectionEnd() {
    objBoundary.visible = false;
    this.visible = true;
    if (selection.type == 'Text') {
        $('#text-editor').css('display', 'none');
        selection.content = $('#text-editor').val();
        animation.context.font = this.style.fontStyle + ' ' + this.style.fontSize + ' ' + this.style.fontFamily;
        selection.width = animation.context.measureText(selection.content).width;
    }
    $('.text-editor-control').hide();
    $('.object-format').hide();
    selection.selecting = false;
}

/**
 * Get type of object
 * @returns {String}
 */
brObject.prototype.getType = function() {
    return this.type;
};

/**
 * Draw this element to context
 * @returns {brObject.prototype@call;draw}
 */
brObject.prototype.draw = function(context) {

};

brObject.prototype.move = function(_position, _zoom) {
    if (this.moving)
        return;
    if (_zoom !== undefined) {
        this.endPosition = _zoom;
    }
    this.startPosition = new brPoint(this.position.x, this.position.y);
    this.endPosition = _position;
    //this.endPosition = new brPoint(_position.x * myCanvas.width / slideWidth, _position.y * myCanvas.width / slideWidth);
    this.accelerator = Math.abs(this.accelerator);
    this.moving = true;
    this.stopX = false;
    this.stopY = false;
}

brObject.prototype.toObject = function() {
    var obj = {};
    for (var key in this) {
        if (typeof (this[key]) !== 'function' && key !== 'image') {
            if (key !== "next" && key !== "prev") {
                if (typeof (this[key]) !== 'string') {
                    obj[key] = {};
                    if (count(this[key]) > 1) {
                        for (var k in this[key]) {
                            obj[key][k] = this[key][k];
                        }
                    }
                    else
                        obj[key] = this[key];
                }
                else {
                    obj[key] = this[key];
                }
            }
        } else {
            if (key == 'image') {
                obj[key] = {};
                obj[key].src = this[key].src;
            }
            if (typeof (this[key]) == 'function') {
                obj[key] = functionName(this[key]);
            }
        }
    }
    return obj;
}

function functionName(fun) {
    var ret = fun.toString();
    ret = ret.substr('function '.length);
    ret = ret.substr(0, ret.indexOf('('));
    return ret;
}

brObject.prototype.update = function(anim) {
    if (animation.editable === false) {
        objBoundary.visible = false;
        if (selection !== undefined)
            selection.paused = false;
    }
    if (this.moving) {
        var timeInterval = anim.getTimeInterval();
        if (Math.abs(this.endPosition.x) !== Math.abs(this.position.x) && this.speed > 0) {
            if (Math.abs(this.endPosition.x - this.position.x) <= Math.abs(this.position.x - this.startPosition.x)) {
                this.accelerator = -Math.abs(this.accelerator);
            }
        }
        if (Math.abs(this.endPosition.y) !== Math.abs(this.position.y) && this.speed.vy > 0) {
            if (Math.abs(this.endPosition.y - this.position.y) <= Math.abs(this.position.y - this.startPosition.y)) {
                this.accelerator = -Math.abs(this.accelerator);
            }
        }
        if (this.speed < this.maxSpeed && this.speed >= 0) {
            this.speed += this.accelerator * timeInterval / 1000;
        }
        //real stop moving
        if (this.speed < 0)
            this.speed = 0;
        if (Math.round(this.endPosition.x) !== Math.round(this.position.x)) {
            this.position.x += (this.endPosition.x > this.position.x ? 1 : -1) * timeInterval / 1000 * this.speed;
        }
        else {
            this.position.x = this.endPosition.x;
            this.startPosition.x = this.endPosition.x;
            this.position.x = this.endPosition.x;
            this.stopX = true;
        }
        if (Math.round(this.endPosition.y) !== Math.round(this.position.y)) {
            this.position.y += (this.endPosition.y > this.position.y ? 1 : -1) * timeInterval / 1000 * this.speed;
        }
        else {
            this.position.y = this.endPosition.y;
            this.startPosition.y = this.endPosition.y;
            this.position.y = this.endPosition.y;
            this.stopY = true;
        }
        if (this.stopX && this.stopY) {
            this.speed = 0;
            this.accelerator = Math.abs(this.accelerator);
            this.moving = false;
        }
    }
    var timeInterval = anim.getTimeInterval();
    if (!this.paused) {
        for (var i = 0; i < this.effects.length; i++) {
            var fn = window[this.effects[i]];
            if (typeof (fn) === 'function') {
                fn(this, timeInterval);
            }
        }
        if (this.effectsInfo !== undefined) {
            for (var i = 0; i < this.effectsInfo.length; i++) {
                if (lifeTime !== 0) {
                    if (this.effectsInfo[i].startTime <= lifeTime && lifeTime < this.effectsInfo[i].endTime) {
                        if (this.effects[i] === "") {
                            this.effectsInfo[i].setup(i, this);
                        }
                    } else if (lifeTime >= this.effectsInfo[i].endTime) {
                        if (this.effects[i] !== "") {
                            this.effectsInfo[i].discard(i, this);
                        }
                    }
                } else {
                    this.effectsInfo[i].discard(i, this);
                }
            }
        }
    }
    if (this.animateTo !== undefined) {
        if (animation.drawPosition === 2) {
            this.position = this.animateTo;
        }
        else {
            this.position = this.orgPos;
        }
    }
    else {
        this.animateTo = new brPoint(this.orgPos.x, this.orgPos.y);
    }
    var translatedObject = animation.camera.translate(this);
    if (animation.editable) {
        this.drawWidth = translatedObject.drawWidth;
        this.drawHeight = translatedObject.drawHeight;
    }
    this.drawPosition = translatedObject.drawPosition;
    this.cameraAnimateTo = translatedObject.animateTo;

    if (this.selecting) {
        objBoundary.startPoint = this.drawPosition;
        objBoundary.width = this.drawWidth;
        objBoundary.height = this.drawHeight;
    }
};

brObject.prototype.addEffect = function(effect, accelerator, maxSpeed, speed, startAccelerator, startTime, endTime, zoom) {
    this.effectsInfo.push(new brEffect(effect, accelerator, maxSpeed, speed, startAccelerator, startTime, endTime, zoom));
};

brObject.prototype.removeEffect = function(index) {
    this.effectsInfo.splice(index, 1);
};

brObject.prototype.checkPosition = function(x, y) {
    if (x >= this.drawPosition.x && x <= this.drawPosition.x + this.drawWidth
            && y >= this.drawPosition.y && y <= this.drawPosition.y + this.drawHeight)
        return true;
    return false;
};

/********************* END **********************/

/********************* CIRCLE *********************/
/**
 * brCircle class definition
 * @param {brPoint} startPoint
 * @param {int} radius
 * @param {object} style
 * @param {speed} speed
 * @param {speed} maxSpeed
 * @param {accelerator} accelerator
 * @returns {brCircle}
 */
function brCircle(startPoint, radius, speed, maxSpeed, accelerator, effects, style) {
    this.index = index;
    this.type = 'Circle';
    this.position = startPoint;
    this.drawPosition = startPoint;
    this.orgPos = new brPoint(startPoint.x, startPoint.y);
    this.startPosition = new brPoint(startPoint.x, startPoint.y);
    this.width = radius * 2;
    this.height = radius * 2;
    this.drawWidth = this.width;
    this.drawHeight = this.height;
    this.speed = speed;
    this.maxSpeed = maxSpeed;
    this.accelerator = accelerator;
    this.startAccelerator = new brAccelerator(accelerator.ax, accelerator.ay);
    this.effects = effects;
    this.style = style;
}

brCircle.prototype = new brObject();
brCircle.prototype.constructor = brCircle;

brCircle.prototype.draw = function(context) {
    context.fillStyle = this.style.background;
    context.lineWidth = this.style.lineWidth;
    context.beginPath();
    if (this.style.position === 'fixed')
        context.arc(this.position.x + this.drawWidth / 2, this.position.y + this.drawHeight / 2, this.drawWidth / 2, 0, 2 * Math.PI, false);
    else
        context.arc(this.drawPosition.x + this.drawWidth / 2, this.drawPosition.y + this.drawHeight / 2, this.drawWidth / 2, 0, 2 * Math.PI, false);
    context.fill();
    context.strokeStyle = this.style.border;
    context.stroke();
};

brCircle.prototype.update = function(anim) {
    brObject.prototype.update.call(this, anim);
    //do other stuff
};

/********************* END **********************/

function brElipse(startPoint, width, height, speed, maxSpeed, accelerator, style, effectsInfo) {
    this.type = 'Elipse';
    this.position = startPoint;
    this.drawPosition = startPoint;
    this.orgPos = new brPoint(startPoint.x, startPoint.y);
    this.startPosition = new brPoint(startPoint.x, startPoint.y);
    this.width = width;
    this.height = height;
    this.drawWidth = this.width;
    this.drawHeight = this.height;
    this.speed = speed;
    this.maxSpeed = maxSpeed;
    this.accelerator = accelerator;
    this.style = style;
    this.startTime = 0;
    this.endTime = 0;
    this.effects = [];
    this.zoom = false;
    this.effectsInfo = effectsInfo;
    this.globalAlpha = 1;
}

brElipse.prototype = new brObject();
brElipse.prototype.constructor = brElipse;

brElipse.prototype.draw = function(context) {
    context.globalAlpha = this.globalAlpha;
    var kappa = .5522848,
            ox = (this.drawWidth / 2) * kappa, // control point offset horizontal
            oy = (this.drawHeight / 2) * kappa, // control point offset vertical
            xe = this.drawPosition.x + this.drawWidth, // x-end
            ye = this.drawPosition.y + this.drawHeight, // y-end
            xm = this.drawPosition.x + this.drawWidth / 2, // x-middle
            ym = this.drawPosition.y + this.drawHeight / 2;       // y-middle
    context.fillStyle = this.style.background;
    context.lineWidth = this.style.lineWidth;
    context.beginPath();
    context.moveTo(this.drawPosition.x, ym);
    context.bezierCurveTo(this.drawPosition.x, ym - oy, xm - ox, this.drawPosition.y, xm, this.drawPosition.y);
    context.bezierCurveTo(xm + ox, this.drawPosition.y, xe, ym - oy, xe, ym);
    context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);
    context.bezierCurveTo(xm - ox, ye, this.drawPosition.x, ym + oy, this.drawPosition.x, ym);
    context.fill();
    context.strokeStyle = this.style.border;
    context.closePath(); // not used correctly, see comments (use to close off open path)
    context.stroke();
    context.globalAlpha = 1;
    /*
     context.beginPath();
     if (this.style.position == 'fixed')
     context.arc(this.position.x + this.drawWidth / 2, this.position.y + this.drawHeight / 2, this.drawWidth / 2, 0, 2 * Math.PI, false);
     else
     context.arc(this.drawPosition.x + this.drawWidth / 2, this.drawPosition.y + this.drawHeight / 2, this.drawWidth / 2, 0, 2 * Math.PI, false);
     
     context.stroke();*/
};

brElipse.prototype.update = function(anim) {
    brObject.prototype.update.call(this, anim);
    //do other stuff
};

/********************* ELIPSE *******************/



/********************* END **********************/

/********************* RECTANGLE **********************/
/**
 * brRectangle class definition
 * @param {brPoint} startPoint
 * @param {int} width
 * @param {int} height
 * @param {speed} speed
 * @param {speed} maxSpeed
 * @param {accelerator} accelerator
 * @param {object} style
 * @returns {brRectangle}
 */
function brRectangle(startPoint, width, height, speed, maxSpeed, accelerator, style, effectsInfo) {
    this.index = index;
    this.type = "Rectangle";
    this.position = startPoint;
    this.drawPosition = startPoint;
    this.startPoint = new brPoint(startPoint.x, startPoint.y);
    this.orgPos = new brPoint(startPoint.x, startPoint.y);
    this.width = width;
    this.height = height;
    this.drawWidth = width;
    this.drawHeight = height;
    this.speed = speed;
    this.maxSpeed = maxSpeed;
    this.accelerator = accelerator;
    this.style = style;
    this.startTime = 0;
    this.endTime = 0;
    this.effects = [];
    this.zoom = false;
    this.effectsInfo = effectsInfo;
    this.globalAlpha = 1;
}

brRectangle.prototype = new brObject();
brRectangle.prototype.constructor = brRectangle;

brRectangle.prototype.draw = function(context) {
    context.globalAlpha = this.globalAlpha;
    context.fillStyle = this.style.background;
    context.lineWidth = this.style.lineWidth;
    context.beginPath();
    context.rect(this.drawPosition.x, this.drawPosition.y, this.drawWidth, this.drawHeight);
    context.fill();
    context.strokeStyle = this.style.border;
    context.stroke();
    context.globalAlpha = 1;
};

/********************* END **********************/

/********************* BOUNDARY *******************/

/**
 * Create a boundary for resizing objects
 * @param {string} name
 * @param {brPoint} startPoint
 * @param {int} width
 * @param {int} height
 * @param {boolean} visible
 * @returns {brBoundary}
 */
function brBoundary(name, startPoint, width, height, visible) {
    this.name = name;
    window[name] = this;
    this.startPoint = startPoint;
    this.endPoint = new brPoint(startPoint.x + width, startPoint.y + height);
    this.width = width;
    this.height = height;
    this.visible = visible;
}

brBoundary.prototype.construct = brBoundary;
brBoundary.prototype.checkPosition = function(x, y) {
    if (x >= this.startPoint.x && x <= this.startPoint.x + this.width
            && y >= this.startPoint.y && y <= this.startPoint.y + this.height)
        return true;
    return false;
};
brBoundary.prototype.draw = function(context) {
    if (this.visible) {
        context.lineWidth = 1;
        context.beginPath();
        context.fillStyle = 'rgba(120, 120, 120, 0.5)';
        context.strokeStyle = 'rgba(120, 120, 120, 0.5)';
        //top left point
        context.lineWidth = 3;
        if (selection !== undefined)
            if (selection.resizable) {
                context.rect(this.startPoint.x, this.startPoint.y, 5, 5);
                //top right point
                context.rect(this.startPoint.x + this.width - 5, this.startPoint.y, 5, 5);
                //bottom left
                context.rect(this.startPoint.x, this.startPoint.y + this.height - 5, 5, 5);
                //bottom right
                context.rect(this.startPoint.x + this.width - 5, this.startPoint.y + this.height - 5, 5, 5);
                context.fill();
            }
        context.rect(this.startPoint.x, this.startPoint.y, this.width, this.height);
        context.stroke();
    }
}
var brBoundaryMouseDown = false;
brBoundary.prototype.mouseDown = function(e) {
    brBoundaryMouseDown = true;
}
brBoundary.prototype.mouseUp = function(e) {
    brBoundaryMouseDown = false;
}
brBoundary.prototype.hover = function(e) {
    var canvas = animation.getContext().canvas;
    switch (inCorner(new brPoint(e.x, e.y), this.startPoint.x, this.startPoint.y, this.width, this.height)) {
        case 1:
            canvas.style.cursor = 'nw-resize';
            break;
        case 2:
            canvas.style.cursor = 'ne-resize';
            break;
        case 3:
            canvas.style.cursor = 'nw-resize';
            break;
        case 4:
            canvas.style.cursor = 'ne-resize';
            break;
        case 0:
            canvas.style.cursor = '';
            break;
    }

}

/********************* END ************************/

/********************* POINT **********************/
/**
 * brPoint class definition
 * @param {int} x
 * @param {int} y
 * @returns {brPoint}
 */
function brPoint(x, y) {
    if (typeof (x) === 'undefined')
        this.x = 0;
    else
        this.x = x;

    if (typeof (y) === 'undefined')
        this.y = 0;
    else
        this.y = y;
}

/********************* END **********************/

/**
 * 
 */
function brImage(startPoint, imageUrl, width, height, speed, maxSpeed, accelerator, style, effectsInfo) {
    this.type = 'Image';
    this.index = index;
    this.position = startPoint;
    this.drawPosition = startPoint;
    this.startPoint = new brPoint(startPoint.x, startPoint.y);
    this.image = new Image();
    this.image.src = imageUrl;
    this.position = new brPoint(startPoint.x * myCanvas.width / slideWidth, startPoint.y * myCanvas.width / slideWidth);
    this.drawPosition = new brPoint(startPoint.x * myCanvas.width / slideWidth, startPoint.y * myCanvas.width / slideWidth);
    this.orgPos = new brPoint(startPoint.x * myCanvas.width / slideWidth, startPoint.y * myCanvas.width / slideWidth);
    this.width = width;
    this.height = height;
    this.speed = speed;
    this.maxSpeed = maxSpeed;
    this.drawWidth = width;
    this.drawHeight = height;
    this.accelerator = accelerator;
    this.effects = [];
    this.style = style;
    this.effectsInfo = effectsInfo;
    this.globalAlpha = 1;
}

brImage.prototype = new brObject();
brImage.prototype.constructor = brImage;

brImage.prototype.draw = function(context) {
    context.globalAlpha = this.globalAlpha;
    if (this.style.position !== 'fixed')
        context.drawImage(this.image, this.drawPosition.x, this.drawPosition.y, this.drawWidth, this.drawHeight);
    else
        context.drawImage(this.image, this.position.x, this.position.y, this.drawWidth, this.drawHeight);
    context.globalAlpha = 1;
};

brImage.prototype.update = function(anim) {
    brObject.prototype.update.call(this, anim);
    //do other stuff
};

/********************* END **********************/

/********************* END **********************/
/**
 * 
 */
function brVideo(startPoint, videoId, src, width, height, speed, maxSpeed, accelerator, effects, style) {
    this.type = 'Video';
    this.position = startPoint;
    this.video = document.getElementById(videoId);
    this.src = src;
    this.video.getElementsByTagName('source')[0].src = this.src;
    this.video.autoplay = true;
    this.state = 'play';
    this.width = width;
    this.video.style.width = width;
    this.height = height;
    this.video.style.height = height;
    this.speed = speed;
    this.maxSpeed = maxSpeed;
    this.accelerator = accelerator;
    this.effects = effects;
    this.style = style;
}

brVideo.prototype = new brObject();
brVideo.prototype.constructor = brVideo;

brVideo.prototype.setCenterPos = function() {
    this.video.style.top = '50%';
    this.video.style.left = '50%';
    this.video.style.marginTop = "-" + this.height / 2 + "px";
    this.video.style.marginLeft = "-" + this.width / 2 + "px";
};

brVideo.prototype.hideVideo = function() {
    this.video.style.display = 'none';
};

brVideo.prototype.showVideo = function() {
    this.video.style.display = '';
};

brVideo.prototype.load = function() {
    var that = this;
    this.video.addEventListener('play', function() {
        interval = window.setInterval(function() {
            animation.getContext().drawImage(this.video, that.position.x, that.position.y, that.width, that.height);
        }, 1000);
    }, false);
    canvas.addEventListener('click', function() {
        if (that.state === 'play') {
            that.video.pause();
            window.clearInterval(interval);
            that.state = 'pause';
        } else {
            that.video.play();
            interval = window.setInterval(function() {
                animation.getContext().drawImage(this.video, that.position.x, that.position.y, that.width, that.height);
            }, 1000);
            that.state = 'play';
        }
    }, false);
    this.video.addEventListener('ended', function() {
        that.state = 'ended';
        clearInterval(interval);
    }, false);
    this.video.load();
};

brVideo.prototype.draw = function(context) {
    context.drawImage(this.video, 0, 0, lastWidth, lastHeight);
};

brVideo.prototype.update = function(anim) {
    brObject.prototype.update.call(this, anim);
    //do other stuff
};

/********************* END **********************/

/********************* STYLE *************************/

var brStyle = function(style) {
    for (var k in style) {
        Object.defineProperty(this, k, {value: style[k],
            writable: true,
            enumerable: true,
            configurable: true});
    }
};
/** 
 * 
 * @param {style object} style
 * @returns {undefined}
 */
brStyle.prototype.addStyle = function(style) {
    for (var k in style) {
        Object.defineProperty(this, k, {value: style[k],
            writable: true,
            enumerable: true,
            configurable: true});
    }
};

brStyle.prototype.getStyle = function() {
    var vals = [];
    for (var key in this) {
        if (this.hasOwnProperty(key)) {
            var obj = {};
            obj[key] = this[key];
            vals.push(obj);
        }
    }
    return vals;
};

brStyle.prototype.removeStyle = function(styleName) {
    delete this[styleName];
    return this.getStyle;
};

brStyle.prototype.addGradientColor = function(styleName, percent, r, g, b, a) {
    var lastIndex;
    var key = styleName + 'Color';
    if (this.hasOwnProperty(key)) {
        lastIndex = this[styleName + 'Color'].length; //styleNameColor include all colors of styleName
    } else {
        this[styleName + 'Color'] = new Array();
        lastIndex = 0;
    }
    this[key][lastIndex] = {percent: percent, r: r, g: g, b: b, a: a, z: a};
    var rgba = 'rgba(' + r + ', ' + g + ', ' + b + ', ' + a + ')';
    this[styleName].addColorStop(percent, rgba);
};

/********************* END **********************/

/********************* SPEED *********************/

/**
 * 
 * @param {int} vx
 * @param {int} vy
 * @returns {brSpeed}
 */
var brSpeed = function(vx, vy) {
    this.vx = vx === undefined ? 0 : vx;
    this.vy = vy === undefined ? 0 : vy;
};

/********************* END *********************/

/********************* ACCELERATOR *********************/

/**
 * 
 * @param {int} ax
 * @param {int} ay
 * @returns {brAccelerator}
 */
var brAccelerator = function(ax, ay) {
    this.ax = ax;
    this.ay = ay;
};

/********************* END *********************/

/********************* BACKGROUND *********************/

/*
 * 
 * @param {brPosition} position
 * @param {int} width
 * @param {int} height
 * @param {style} style
 * @returns {brBackground}
 */
var brBackground = function(position, width, height, style) {
    this.position = position;
    this.width = width;
    this.height = height;
    this.style = style;
}

brBackground.prototype.draw = function(context) {
    context.fillStyle = this.style.backgroundColor;
    context.rect(this.position.x, this.position.y, this.width, this.height);
    context.fill();
}

/********************* END *********************/

/********************* OBJECT LIST **********************/

function brObjectList() {

}

brObjectList.prototype = {
    length: 0,
    first: null,
    last: null
};

brObjectList.prototype = new brObjectList();

brObjectList.prototype.append = function(node) {
    if (this.first === null) {
        node.prev = null;
        node.next = null;
        this.first = node;
        this.last = node;
    } else {
        node.prev = this.last;
        this.last.next = node;
        this.last = node;
    }
    this.length++;
    return node;
};

brObjectList.prototype.insertAfter = function(node, newNode) {
    newNode.prev = node;
    newNode.next = node.next;
    node.next.prev = newNode;
    node.next = newNode;
    if (newNode.prev === this.last) {
        this.last = newNode;
    }
    this.length++;
    return newNode;
};

brObjectList.prototype.insertBefore = function(node, newNode) {
    this.first = newNode;
    node.prev = newNode;
    newNode.prev = null;
    newNode.next = node;
    this.length++;
    return newNode;
};

brObjectList.prototype.remove = function(node) {
    if (this.length > 1) {
        if (node.prev !== null)
            node.prev.next = node.next;
        if (node.next !== null)
            node.next.prev = node.prev;
        if (node === this.first) {
            this.first = node.next;
        }
        if (node === this.last) {
            this.last = node.prev;
        }
    } else {
        this.first = null;
        this.last = null;
    }
    node.prev = null;
    node.next = null;
    this.length--;
};

brObjectList.prototype.getByIndex = function(index) {
    var curObject = this.first;
    while (curObject !== null) {
        if (curObject.index === index) {
            return curObject;
        }
        curObject = curObject.next;
    }
    return null;
};

brObjectList.prototype.findByName = function(name) {
    var curObject = this.first;
    while (curObject !== null) {
        if (curObject.name !== undefined)
            if (curObject.name === name) {
                return curObject;
            }
        curObject = curObject.next;
    }
    return null;
}

brObjectList.prototype.moveToLast = function(node) {
    if (node.next == null)
        return;
    //link last and next first
    node.next.prev = node.prev;
    if (node.prev == null)
        this.first = node.next;
    if (node.prev !== null)
        node.prev.next = node.next;

    //make the last node point to node
    this.last.next = node;
    node.prev = this.last;

    //then last is node
    node.next = null;
    this.last = node;
};

brObjectList.prototype.toJSON = function() {
    var curObject = this.first;
    var objs = [];
    while (curObject !== null) {
        objs.push(curObject.toObject());
        curObject = curObject.next;
    }
    return JSON.stringify(objs);
};
/********************* END **********************/

/********************* EFFECTS *********************/

//BOKEH
/**
 * 
 * @param {int} timeInterval
 * @returns {void}
 */
function bokehEffect(object, timeInterval) {
    // physics globals
    if (animation.editable === true)
        return;
    object.position.y += object.speed.vy * timeInterval / 1000;
    object.position.x += object.speed.vx * timeInterval / 1000;
    if (Math.abs(object.speed.vx) <= object.maxSpeed.vx) {
        object.speed.vx += object.accelerator.ax * timeInterval / 1000;
    } else {
        object.speed.vx = (object.speed.vx > 0 ? 1 : -1) * object.maxSpeed.vx;
    }
    if (Math.abs(object.speed.vy) <= object.maxSpeed.vy) {
        object.speed.vy += object.accelerator.ay * timeInterval / 1000;
    }
    else
        object.speed.vy = (object.speed.vy > 0 ? 1 : -1) * object.maxSpeed.vy;
    if (object.position.x > canvasWidth - object.width / 2 + 3000) {
        object.accelerator.ax = -parseInt(Math.random() * 25);
        index++;
    }
    if (object.position.x < -object.width / 2 - 3000) {
        object.accelerator.ax = parseInt(Math.random() * 25);
        index++;
    }
    if (object.position.y > canvasHeight - object.height / 2) {
        object.accelerator.ay = -parseInt(Math.random() * 25);
        index++;
    }
    if (object.position.y < -object.height / 2) {
        object.accelerator.ay = parseInt(Math.random() * 25);
        index++;
    }
}

/******************** END **********************/

/******************** BOUNCE *******************/

/**
 * 
 * @param {brObject} object
 * @param {int} timeInterval
 * @returns {void}
 */
function bounceEffect(object, timeInterval) {
    if (!animation.editable) {
        // physics globals
        if (object.position.x < -object.width || object.position.x > canvasWidth + object.width)
            return;
        var gravity = 1500; // pixels / second^2
        var collisionDamper = 0.8; // 80% velocity lost when
        var floorFriction = 100; // pixels / second^2
        // gravity
        object.speed.vy += gravity * timeInterval / 1000;
        // position
        object.position.y += object.speed.vy * timeInterval / 1000;
        object.position.x += object.speed.vx * timeInterval / 1000;
        // floor condition
        if (object.position.y > (canvasHeight - object.height - 0.5 * object.height)) {
            object.position.y = canvasHeight - object.height - 0.5 * object.height;
            object.speed.vy *= -1;
            object.speed.vy *= collisionDamper;
        }
        // floor friction
        if (object.position.y === canvasHeight - object.height - 0.5 * object.height) {
            if (object.speed.vx > 0.1) {
                object.speed.vx -= floorFriction * timeInterval /
                        1000;
            }
            else if (object.speed.vx < -0.1) {
                object.speed.vx += floorFriction * timeInterval /
                        1000;
            }
            else {
                object.speed.vx = 0;
            }
        }
        // ceiling condition
        if (object.position.y < 0) {
            object.position.y = 0;
            object.speed.vy *= -1;
            object.speed.vy *= collisionDamper;
        }
        // right wall condition
        if (object.position.x > (canvasWidth - object.width) && object.position.x < canvasWidth + object.width) {
            object.position.x = canvasWidth - object.width;
            object.speed.vx *= -1;
            object.speed.vx *= collisionDamper;
        }
        // left wall condition
        if (object.position.x < 0 && object.position.x > -object.width) {
            object.position.x = 0;
            object.speed.vx *= -1;
            object.speed.vx *= collisionDamper;
        }
    }
}

/******************** END **********************/

/******************** FLOAT EFFECT *************/

/**
 * 
 * @param {brObject} object
 * @param {int} timeInterval
 * @returns {void}
 */
var objects = {};
function floatEffect(object, timeInterval) {
    objects = object;
    var diff = 10;
    object.position.y += object.speed.vy * timeInterval / 1000;
    object.position.x += object.speed.vx * timeInterval / 1000;
    if (Math.abs(object.speed.vx) <= object.maxSpeed.vx) {
        object.speed.vx += object.accelerator.ax * timeInterval / 1000;
    } else {
        object.speed.vx = (object.speed.vx > 0 ? 1 : -1) * object.maxSpeed.vx;
    }
    if (Math.abs(object.speed.vy) <= object.maxSpeed.vy) {
        object.speed.vy += object.accelerator.ay * timeInterval / 1000;
    }
    else
        object.speed.vy = (object.speed.vy > 0 ? 1 : -1) * object.maxSpeed.vy;

    if (object.position.x > object.orgPos.x + diff) {
        object.accelerator.ax = -parseInt(Math.random() * 25);
        index++;
    }
    if (object.position.x < object.orgPos.x - diff) {
        object.accelerator.ax = parseInt(Math.random() * 25);
        index++;
    }
    if (object.position.y > object.orgPos.y + diff) {
        object.accelerator.ay = -parseInt(Math.random() * 25);
        index++;
    }
    if (object.position.y < object.orgPos.y - diff) {
        object.accelerator.ay = parseInt(Math.random() * 25);
        index++;
    }
}

/******************** END **********************/

//CLOUD
/**
 * 
 * @param {int} timeInterval
 * @returns {void}
 */
function cloudEffect(object, timeInterval) {
    // physics globals
    object.position.x += object.speed.vx * timeInterval / 1000;
    if (Math.abs(object.speed.vx) <= object.maxSpeed.vx) {
        object.speed.vx += object.accelerator.ax * timeInterval / 1000;
    } else {
        object.speed.vx = (object.speed.vx > 0 ? 1 : -1) * object.maxSpeed.vx;
    }
    if (object.position.x > canvasWidth - object.width) {
        object.accelerator.ax = -parseInt(Math.random() * 25);
        // index++;
    }
    if (object.position.x < 0) {
        object.accelerator.ax = parseInt(Math.random() * 25);
        //index++;
    }
}

/******************** END **********************/

//FADE IN
/**
 * 
 * @param {type} object
 * @param {type} timeInterval
 * @returns {undefined}
 */
function fadeInEffect(object, timeInterval) {
    var gl_alpha = object.globalAlpha;
    if(gl_alpha !== undefined) {
        if (gl_alpha < 0.01) {
            gl_alpha = 0;
        } else {
            var gl_alpha = gl_alpha - timeInterval / 1000;
            if (gl_alpha < 0) {
                gl_alpha = 0;
            }
        }
        object.globalAlpha = gl_alpha;
    }
}
/******************** END **********************/
//FADE OUT
/**
 * 
 * @param {type} object
 * @param {type} timeInterval
 * @returns {undefined}
 */
function fadeOutEffect(object, timeInterval) {
    var gl_alpha = object.globalAlpha;
    if(gl_alpha !== undefined) {
        if (gl_alpha > 1) {
            gl_alpha = 1;
        } else {
            var gl_alpha = parseFloat(gl_alpha) + parseFloat(timeInterval / 1000);
            if (gl_alpha > 1) {
                gl_alpha = 1;
            }
        }
        object.globalAlpha = gl_alpha;
    }
}
/******************** END **********************/
//PULSE
/**
 * 
 * @param {type} object
 * @param {type} timeInterval
 * @returns {undefined}
 */

function pulseEffect(object, timeInterval) {
    var rate = object.width / object.height;
    var zoom = object.zoom;
    var delta = 500 * timeInterval / 1000;
    if (zoom !== undefined && zoom) {
        if (object.drawWidth + delta < 1.5 * object.width) {
            object.drawWidth = object.drawWidth + delta;
        } else {
            object.drawWidth = 1.5 * object.width;
            object.zoom = false;
        }
    } else {
        if (object.drawWidth - delta > object.width) {
            object.drawWidth = object.drawWidth - delta;
        } else {
            object.drawWidth = object.width;
        }
    }
    object.drawHeight = object.drawWidth / rate;
}
/******************** END **********************/

/******************** CAMERA **********************/

/**
 * 
 * @param {brPoint} _position
 * @param {float} _zoom
 * @returns {void}
 */
var cameraAccelerate = 30;
function brCamera(_position, _zoom) {
    this.startPosition = new brPoint(_position.x, _position.y);
    this.position = _position;
    this.endPosition = _position;
    this.zoomRatio = _zoom;
    this.startZoomRatio = _zoom;
    this.endZoomRatio = _zoom;
    this.speed = new brSpeed(0, 0);
    this.maxSpeed = new brSpeed(5000, 5000);
    this.accelerate = new brAccelerator(cameraAccelerate, cameraAccelerate);
    this.moving = false;
}

brCamera.prototype.getZoomLevel = function() {
    return this.zoomRatio;
}

/**
 * 
 * @param {brPoint} _position
 * @param {_zoom} _zoom
 * @returns {void}
 */
brCamera.prototype.move = function(_position, callback) {
    if (this.moving)
        return;
    this.callback = callback;
    this.endPosition = new brPoint(_position.x * myCanvas.width / slideWidth, _position.y * myCanvas.width / slideWidth);
    //calc the ratio
    var deltaX = 1 + Math.abs(this.endPosition.x * myCanvas.width / slideWidth - camera.position.x);
    console.log(deltaX);
    var deltaY = 1 + Math.abs(this.endPosition.y * myCanvas.width / slideWidth - camera.position.y);
    console.log(deltaY);
    if (deltaX > deltaY) {
        if (deltaY > 0) {
            camera.accelerate.ay = 2000 * deltaY / deltaX;
        }
    }
    else {
        if (deltaX > 0) {
            camera.accelerate.ax = 2000 * deltaX / deltaY;
        }
    }
    this.accelerate.ax = Math.abs(this.accelerate.ax);
    this.accelerate.ay = Math.abs(this.accelerate.ay);
    this.movementType = 1;
    this.moving = true;
    this.stopX = false;
    this.stopY = false;
    this.called = false;
}

brCamera.prototype.zoom = function(_position, _zoom) {

}

brCamera.prototype.rotating = function(_position, _zoom) {

}

brCamera.prototype.update = function(anim) {
    if (this.moving) {
        var timeInterval = anim.getTimeInterval();
        if (Math.abs(this.endPosition.x) !== Math.abs(this.position.x) && this.speed.vx > 0) {
            if (Math.abs(this.endPosition.x - this.position.x) <= Math.abs(this.position.x - this.startPosition.x)) {
                this.accelerate.ax = -Math.abs(this.accelerate.ax);
                this.movementType = -1;
            }
        }
        if (Math.abs(this.endPosition.y) !== Math.abs(this.position.y) && this.speed.vy > 0) {
            if (Math.abs(this.endPosition.y - this.position.y) <= Math.abs(this.position.y - this.startPosition.y)) {
                this.accelerate.ay = -Math.abs(this.accelerate.ay);
                this.movementType = -1;
            }
        }
        if (!this.stopX)
            if (this.speed.vx < this.maxSpeed.vx && this.speed.vx >= 0) {
                this.speed.vx += this.accelerate.ax * timeInterval / 1000;
            }
        if (!this.stopY)
            if (this.speed.vy < this.maxSpeed.vy && this.speed.vy >= 0) {
                this.speed.vy += this.accelerate.ay * timeInterval / 1000;
            }
        var curObject = objectList.first;
        for (i = 0; i < 200; i++) {
            if (this.position.x - this.endPosition.x !== 0) {
                curObject.accelerator.ax = curObject.width / 10 * ((this.position.x - this.endPosition.x) / Math.abs(this.position.x - this.endPosition.x)) * this.speed.vx;
            }
            if (this.position.y - this.endPosition.y !== 0) {
                curObject.accelerator.ay = curObject.width / 10 * ((this.position.y - this.endPosition.y) / Math.abs(this.position.y - this.endPosition.y)) * this.speed.vy;
            }
            curObject = curObject.next;
        }
        //real stop moving
        if (this.speed.vx < 0)
            this.speed.vx = 0;
        if (this.speed.vy < 0)
            this.speed.vy = 0;
        if (!this.stopX) {
            if (Math.round(this.endPosition.x) !== Math.round(this.position.x)) {
                var delta = (this.endPosition.x > this.position.x ? 1 : -1) * timeInterval / 1000 * this.speed.vx;
                if (this.speed.vx == 0) {
                    this.position.x = this.endPosition.x;
                }
                else
                    this.position.x += delta;
            }
            else {
                this.position.x = this.endPosition.x;
                this.speed.vx = 0;
                this.startPosition.x = this.endPosition.x;
                this.position.x = this.endPosition.x;
                this.accelerate.ax = Math.abs(this.accelerate.ax);
                this.stopX = true;
            }
        }
        if (!this.stopY) {
            if (Math.round(this.endPosition.y) !== Math.round(this.position.y)) {
                var delta = (this.endPosition.y > this.position.y ? 1 : -1) * timeInterval / 1000 * this.speed.vy;
                if (this.speed.vy == 0)
                    this.position.y = this.endPosition.y;
                else
                    this.position.y += delta;
            }
            else {
                this.position.y = this.endPosition.y;
                this.speed.vy = 0;
                this.startPosition.y = this.endPosition.y;
                this.position.y = this.endPosition.y;
                this.accelerate.ay = Math.abs(this.accelerate.ay);
                this.stopY = true;
            }
        }
        if (this.stopX && this.stopY) {
            this.moving = false;
            var curObject = objectList.first;
            for (i = 0; i < 200; i++) {
                curObject.accelerator.ax = curObject.startAccelerator.ax;
                curObject.accelerator.ay = curObject.startAccelerator.ay;
                curObject = curObject.next;
            }
        }
        if (this.movementType === -1)
            if (this.speed.vx < 500 * myCanvas.width / slideWidth || this.speed.vy < 500 * myCanvas.width / slideWidth) {
                if (typeof (this.callback === 'function')) {
                    if (this.callback !== undefined) {
                        this.callback();
                        this.called = true;
                    }
                }
            }
    }
};

/*
 * 
 * @param {brAccelerator)} a
 * @returns {void}
 */
brCamera.prototype.setAccelerate = function(a) {
    this.accelerate = a;
};

brCamera.prototype.translate = function(object) {
    var result = {
        drawPosition: new brPoint(object.position.x - this.position.x, object.position.y - this.position.y),
        drawWidth: object.width,
        drawHeight: object.height
    };
    if (object.animateTo !== undefined) {
        result.animateTo = new brPoint(object.animateTo.x - this.position.x, object.animateTo.y - this.position.y);
    }
    return result;
};

/******************** END **********************/

/******************** TEXT *********************/

/**
 * brRectangle class definition
 * @param {string} name
 * @param {string} content
 * @param {brPoint} startPoint
 * @param {int} width
 * @param {int} height
 * @param {speed} speed
 * @param {speed} maxSpeed
 * @param {accelerator} accelerator
 * @param {brEffect} effects
 * @param {object} style
 * @returns {brText}
 */
function brText(name, content, startPoint, width, height, speed, maxSpeed, accelerator, style, effectsInfo) {
    this.index = index;
    this.name = name;
    window[name] = this;
    this.type = "Text";
    this.content = content;
    this.startPoint = startPoint;
    this.position = new brPoint(startPoint.x * myCanvas.width / slideWidth, startPoint.y * myCanvas.width / slideWidth);
    this.drawPosition = new brPoint(startPoint.x * myCanvas.width / slideWidth, startPoint.y * myCanvas.width / slideWidth);
    this.orgPos = new brPoint(startPoint.x * myCanvas.width / slideWidth, startPoint.y * myCanvas.width / slideWidth);
    this.width = width;
    this.height = height;
    this.drawWidth = width;
    this.drawHeight = height;
    this.speed = speed;
    this.maxSpeed = maxSpeed;
    this.accelerator = accelerator;
    this.effects = [];
    this.style = style;
    var styles = {};
    for (var key in style) {
        styles[key] = '' + style[key];
    }
    this.orgStyle = styles;
    if (this.style.fontStyle === undefined)
        this.style.fontStyle = 'normal';
    if (this.style.fontSize === undefined)
        this.style.fontSize = '12px';
    if (this.style.fontFamily === undefined)
        this.style.fontFamily = 'Tahoma';
    var fontSize = parseFloat(this.style.fontSize);
    fontSize = fontSize * myCanvas.width / slideWidth;
    this.style.fontSize = fontSize + 'px';
    this.resizable = false;
    this.zoom = false;
    this.effectsInfo = effectsInfo;
    this.globalAlpha = 1;
}

brText.prototype = new brObject();
brText.prototype.constructor = brText;

brText.prototype.draw = function(context) {
    if (this.visible === false)
        return;
    context.globalAlpha = this.globalAlpha;
    context.fillStyle = this.style.fontColor;
    context.font = this.style.fontStyle + ' ' + this.style.fontSize + ' ' + this.style.fontFamily;
    this.width = context.measureText(this.content).width;
    if (this.style.position == 'fixed') {
        if (this.cameraAnimateTo !== undefined && animation.drawPosition == 2) {
            context.fillText(this.content, this.cameraAnimateTo.x, this.cameraAnimateTo.y - 7 + this.drawHeight);
        }
        else
            context.fillText(this.content, this.position.x, this.position.y - 7 + this.drawHeight);
    }
    else {
        if (this.cameraAnimateTo !== undefined && animation.drawPosition == 2) {
            context.fillText(this.content, this.cameraAnimateTo.x, this.cameraAnimateTo.y - 7 + this.drawHeight);
        }
        else
            context.fillText(this.content, this.drawPosition.x, this.drawPosition.y - 7 + this.drawHeight);
    }
    context.globalAlpha = 1;
};

/******************** END **********************/

/**
 * Interaction
 */
document.onreadystatechange = function() {
    var state = document.readyState;
    if (state == 'interactive') {
        init();
    } else if (state == 'complete') {
        initOnCompleteLoad();
    }
}

function init() {
    //console.log('init');
}

var selection, currentCameraPos = 0;
function initOnCompleteLoad() {
    var canvas = document.getElementById('myCanvas');
    canvas.onclick = function(e) {
        if (animation.editable === false)
        {
            if (camera.moving)
                return;
            if (currentCameraPos < cameraPositions.length - 1)
                currentCameraPos++;
            else
                return;
            if (cameraPositions[currentCameraPos] !== undefined) {
                if (!animation.live) {
                    $('ul.slides li.selected').removeClass('selected');
                    $('ul.slides li').get(currentCameraPos).className = 'selected';
                }
                camera.move(cameraPositions[currentCameraPos], function() {
                    /*if (slideAnimations[currentCameraPos] !== undefined) {
                     eval(slideAnimations[currentCameraPos]); 
                     }*/
                    var curObject = objectList.first;
                    while (curObject !== null) {
                        if (curObject.type == 'Circle') {
                            curObject = curObject.next;
                            continue;
                        }
                        if (curObject.position.x >= camera.endPosition.x && curObject.position.x <= camera.endPosition.x + myCanvas.width) {
                            if (curObject.animateTo !== undefined && !curObject.animated) {
                                console.log(curObject.animateTo);
                                curObject.move(new brPoint(curObject.animateTo.x, curObject.animateTo.y));
                                curObject.animated = true;
                            }
                        }
                        curObject = curObject.next;
                    }
                });
            }
        }
    };
    var dragging = false;
    var mouseDown = false;
    var startX = 0;
    var startY = 0;
    var lastX = 0;
    var lastY = 0;
    var objStartX = 0;
    var objStartY = 0;
    canvas.onmousemove = function(e) {
        if (animation === undefined || camera === undefined || animation.editable === false)
            return;
        var deltaX = e.x + camera.position.x - startX;
        var deltaY = e.y + camera.position.y - startY;
        var x = e.x - parseInt($(this).offset().left);
        var y = e.y - parseInt($(this).offset().top) + $(document).scrollTop();
        if ($('.button-set.control>li.selected:not(.select)').length > 0) {
            if (selection !== undefined) {
                selection.width = Math.abs(objStartX - x);
                selection.height = Math.abs(objStartY - y);
                if (x < objStartX) {
                    selection.position.x = x + camera.endPosition.x;
                }
                if (y < objStartY) {
                    selection.position.y = y + camera.endPosition.y;
                }
            }
            return;
        }
        if (mouseDown) {
            if (selection !== undefined) {
                if (selection.paused) {
                    if (deltaX != 0 && deltaY != 0)
                        dragging = true;
                    if (objBoundary.mouseMove !== undefined) {
                        var eventArgs = {};
                        eventArgs.x = x;
                        eventArgs.y = y;
                        eventArgs.button = mouseDown;
                        eventArgs.deltaX = deltaX;
                        eventArgs.deltaY = deltaY;
                        objBoundary.mouseMove(eventArgs);
                    }
                    if (selection.mouseMove !== undefined) {
                        var eventArgs = {};
                        eventArgs.x = x;
                        eventArgs.y = y;
                        selection.mouseMove(eventArgs);
                    }

                }
            }
            else {
                //move the camera
                console.log(startX + ' - ' + startY + ' . ' + objStartX + ' - ' + objStartY);
                camera.position.x -= e.x - lastX;
                lastX = e.x;
                camera.position.y -= e.y - lastY;
                lastY = e.y;
            }
        } else {
            if (selection !== undefined) {
                if (selection.checkPosition(x, y)) {
                    if (selection.hover !== undefined) {
                        var eventArgs = {};
                        eventArgs.x = x;
                        eventArgs.y = y;
                        selection.hover(eventArgs);
                    }
                }
                else {

                }
                if (objBoundary.checkPosition(x, y)) {
                    if (objBoundary.mouseMove !== undefined) {
                        var eventArgs = {};
                        eventArgs.x = x;
                        eventArgs.y = y;
                        eventArgs.button = mouseDown;
                        objBoundary.mouseMove(eventArgs);
                    }
                }
                else {
                    if (objBoundary.mouseOut !== undefined) {
                        var eventArgs = {};
                        eventArgs.x = x;
                        eventArgs.y = y;
                        objBoundary.mouseOut(eventArgs);
                    }
                }
            }
        }
    }

    var newObject = false;
    canvas.onmousedown = function(e) {
        if (animation.editable === false)
            return;
        mouseDown = true;
        lastX = e.x;
        lastY = e.y;
        startX = e.x + camera.position.x;
        startY = e.y + camera.position.y;
        var x = e.x - parseInt($(this).offset().left);
        objStartX = x;
        var y = e.y - parseInt($(this).offset().top) + $(document).scrollTop();
        objStartY = y;
        if ($('.button-set.control>li.selected:not(.select)').length > 0) {
            var className = $('.button-set.control>li.selected').get(0).className;
            var objName = className.split(' ')[0];
            switch (objName.toLowerCase()) {
                case "circle":
                    var circle = new brElipse(new brPoint(x + camera.position.x, y + camera.position.y), 0, 0, 0, 0, new brAccelerator(500, 500), {background: $('.object-format .background-color li.selected').attr('value'), borderWidth: 3, border: $('.object-format .border-color li.selected').attr('value')}, []);
                    objectList.append(circle);
                    circle.paused = true;
                    circle.selectable = true;
                    selection = circle;
                    break;
                case "rectangle":
                    var rect = new brRectangle(new brPoint(x + camera.position.x, y + camera.position.y), 0, 0, 0, 0, new brAccelerator(500, 500), {background: $('.object-format .background-color li.selected').attr('value'), borderWidth: 3, border: $('.object-format .border-color li.selected').attr('value')}, []);
                    objectList.append(rect);
                    rect.paused = true;
                    rect.selectable = true;
                    selection = rect;
                    break;
                case "text":
                    var text = new brText("text-" + objectList.length, "text", new brPoint((x + camera.position.x) * slideWidth / myCanvas.width, (y + camera.position.y) * slideWidth / myCanvas.width), 100, 100, 0, 0, 500, [], {fontSize: $('.font-size select').val(), fontFamily: "Tahoma", fontStyle: "normal"});
                    objectList.append(text);
                    selection = objectList.last;
                    text.selectable = true;
                    text.width = 100;
                    text.height = 100;
                    break;
            }
            return false;
        }
        newObject = false;
        var curObject = animation.objectList.last;
        var noObject = true;
        while (curObject !== null) {
            if (curObject.selectable) {
                if (curObject.checkPosition(x, y)) {
                    if (selection !== undefined) {
                        selection.paused = false;
                        if (curObject.selectionEnd !== undefined) {
                            var args = {};
                            args.x = x;
                            args.y = y;
                            curObject.selectionEnd(args);
                        }
                    }
                    selection = curObject;
                    curObject.paused = true;
                    curObject.startPosition = new brPoint(curObject.position.x, curObject.position.y);
                    this.style.cursor = 'move';
                    if (curObject.selectionStart !== undefined) {
                        var args = {};
                        args.x = x;
                        args.y = y;
                        curObject.selectionStart(args);
                    }
                    if (curObject.mouseDown !== undefined) {
                        var args = {};
                        args.x = x;
                        args.y = y;
                        curObject.mouseDown(args);
                    }
                    if (objBoundary.checkPosition(x, y)) {
                        if (objBoundary.mouseDown !== undefined) {
                            var eventArgs = {};
                            eventArgs.x = x;
                            eventArgs.y = y;
                            eventArgs.button = mouseDown;
                            objBoundary.mouseDown(eventArgs);
                        }
                    }
                    noObject = false;
                    break;
                }
            }
            curObject = curObject.prev;
        }
        if (noObject) {
            if (selection !== undefined) {
                selection.paused = false;
                if (selection.selectionEnd !== undefined) {
                    var args = {};
                    args.x = x;
                    args.y = y;
                    selection.selectionEnd(args);
                }
                selection = undefined;
            }
        }
        if (curObject === null) {
            releaseObject(selection);
        }
        //set effects menu of curObject
        if (objBoundary.visible) {
            $('.animation-list').html('');
            if (selection.effectsInfo !== undefined) {
                for (var i = 0; i < selection.effectsInfo.length; i++) {
                    var action = selection.effectsInfo[i].type.toLowerCase();
                    action = action.slice(0, action.indexOf('effect'));
                    var animation_name = capitaliseFirstLetter(action);
                    var start_time = selection.effectsInfo[i].startTime;
                    var li = '<li class="animation">' +
                            '<i class="fa fa-star"></i>' +
                            '<span class="animate-name" title="' + animation_name + '">' + animation_name + '</span>' +
                            '<input class="animate-timer" type="number" min="1" max="100" value="' + start_time + '"/>' +
                            '<span>s</span>' +
                            '<i class="fa fa-clear"></i>' +
                            '</li>';
                    $('.animation-list').append(li);
                }
            }
        } else {
            $('.animation-list').html('<span class="select-hint">Select an object</span>');
        }
    };

    function releaseObject(object) {
        if (object !== undefined && !newObject) {
            //object.style.border = object.style.oldBorder;
            //object.paused = false;
            object = undefined;
        }
    }

    canvas.onmouseup = function(e) {
        if (e === undefined)
            return;
        if (animation.editable === false)
            return;
        resizing = false;
        moving = false;
        dragging = false;
        mouseDown = false;
        resizingPos = 0;
        var slideIndex = parseInt($('.slides-container li.selected').children('.slide-index').text());
        editComplete();
        cameraPositions[slideIndex - 1] = new brPoint(camera.position.x * slideWidth / myCanvas.width, camera.position.y * slideWidth / myCanvas.width);
        if ($('.button-set.control>li.selected:not(.select)').length > 0) {
            selection.paused = false;
            selection = undefined;
        }
        this.style.cursor = '';
        if (selection !== undefined) {
            var x = e.x - parseInt($(this).offset().left);
            var y = e.y - parseInt($(this).offset().top) + $(document).scrollTop();
            if (mouseDown && !dragging && selection.checkPosition(x, y)) {
                //Call click event
                if (selection.click !== undefined) {
                    var eventArgs = {};
                    eventArgs.x = x;
                    eventArgs.y = y;
                    selection.click(eventArgs);
                }
            } else if (mouseDown) {
                //Call mouseUp event
                if (selection.mouseUp !== undefined) {
                    var eventArgs = {};
                    eventArgs.x = x;
                    eventArgs.y = y;
                    selection.mouseUp(eventArgs);
                }
            }
            return;
        }
        releaseObject(selection);
    }

    canvas.onmouseleave = function(e) {
        if (animation.editable === false)
            return;
        this.onmouseup();
    }

    canvas.ondblclick = function(e) {
        if (animation.editable === false)
            return;
        if ($('.button-set.control>li.selected:not(.select)').length > 0) {
            return;
        }
        if (selection == undefined)
            return;
        switch (selection.type) {
            case "Text":
                $('#text-editor').css('left', selection.drawPosition.x + 'px');
                $('#text-editor').css('top', selection.drawPosition.y + 'px');
                $('#text-editor').width(selection.drawWidth);
                $('#text-editor').height(selection.drawHeight);
                $('#text-editor').css('font-size', selection.style.fontSize);
                $('#text-editor').css('font-family', selection.style.fontFamily);
                $('#text-editor').css('font-weight', selection.style.fontStyle);
                $('#text-editor').css('display', '');
                setTimeout(function() {

                }, 100);
                $('#text-editor').focus();
                $('#text-editor').scrollTop(0);
                animation.context.font = selection.style.fontStyle + ' ' + selection.style.fontSize + ' ' + selection.style.fontFamily;
                $('#text-editor').width(animation.context.measureText(selection.content).width);
                break;
        }
        objBoundary.visible = false;
        selection.visible = false;
    }

}

document.onkeyup = canvasKeyUp;

function canvasKeyUp(e) {
    switch (e.keyCode) {
        case 46:
            if (selection !== undefined) {
                objectList.remove(selection);
                objBoundary.visible = false;
                $('.object-format').hide();
                $('.text-editor-control').hide();
            }
            break;
    }
}

function inCorner(e, x, y, width, height) {
    if (e.x >= x - 5 && e.x <= x + 5 && e.y) { //left
        if (e.y >= y - 5 && e.y <= y + 5) { //top
            return 1;
        }
        if (e.y >= y + height - 5 && e.y <= y + height + 5) { //bottom
            return 4;
        }
    }
    if (e.x >= x + width - 5 && e.x <= x + width + 5 && e.y) { //right
        if (e.y >= y - 5 && e.y <= y + 5) { //top
            return 2;
        }
        if (e.y >= y + height - 5 && e.y <= y + height + 5) { //bottom
            return 3;
        }
    }
    return 0;
}

function count(object) {
    var count = 0;
    for (var key in object) {
        count++;
    }
    return count;
}

var data = {};

function save() {
    var elements = [];
    var curObject = objectList.first;
    while (curObject !== null) {
        if (curObject.type !== 'Circle') {
            var delta = slideWidth / myCanvas.width
            if (curObject.type == 'Elipse' || curObject.type == 'Rectangle')
                delta = 1;
            curObject.startPoint = new brPoint(curObject.position.x * delta, curObject.position.y * delta);
            elements.push(curObject.toObject());
        }
        curObject = curObject.next;
    }
    data = {
        slideWidth: 1366,
        background: {
            type: "bokeh",
            backgroundColor: "#d45729",
            circleBackground: "rgba(230, 126, 34, 0.3)",
            circleBorder: "rgba(230, 126, 34, 0.5)",
            numberOfCircle: 200
        },
        camera: {
            accelerate: [2000, 2000]
        },
        cameraPositions: cameraPositions,
        slideAnimations: slideAnimations,
        elements: elements
    };
    var images = [];
    $('.slides img').each(function() {
        images.push($(this).attr('src'));
    });
    var bretId = window.location.href.split('/')[5];
    if (bretId != undefined) {
        bretId = '/' + bretId;
    }
    else
        bretId = '';
    console.log(data.elements[0].index);
    $.post('/bret/ws/savebret' + bretId, {
        'data': JSON.stringify(data),
        'name': $('#name').val(),
        'description': $('#description').val(),
        'images': JSON.stringify(images)
    }).done(function(data) {
        window.history.pushState({}, 'Bret Editor', '/bret/edit' + bretId);
    });
}

function brEffect(type, accelerator, maxSpeed, speed, startAccelerator, startTime, endTime, zoom) {
    this.type = type;
    this.accelerator = accelerator;
    this.maxSpeed = maxSpeed;
    this.speed = speed;
    this.startAccelerator = startAccelerator;
    this.startTime = startTime;
    this.endTime = endTime;
    this.zoom = zoom;
}

brEffect.prototype = new brObject();
brEffect.prototype.constructor = brEffect;

brEffect.prototype.setup = function(index, object) {
    object.effects[index] = this.type;
    switch (this.type) {
        case 'fadeInEffect':
        case 'fadeOutEffect':
            break;
        default:
            object.accelerator = this.accelerator;
            object.maxSpeed = this.maxSpeed;
            object.speed = this.speed;
            object.startAccelerator = this.startAccelerator;
            object.zoom = this.zoom;
            break;
    }
};
brEffect.prototype.discard = function(index, object) {
    object.effects[index] = '';
};


//sync

var connectionId = parseInt(window.location.href.split('/')[5]);

function loadData(progressFunc, completeFunc) {
    function getXMLHttpRequest() {
        if (window.XMLHttpRequest) {
            return new window.XMLHttpRequest;
        } else {
            try {
                return new ActiveXObject("MSXML2.XMLHTTP");
            } catch (ex) {
                return null;
            }
        }
    }

    function handler() {
        console.log(oReq.readyState);
        if (oReq.readyState == 4 /* complete */) {
            if (oReq.status == 200) {
                completeFunc(oReq.responseText);
            }
        }
    }

    var oReq = getXMLHttpRequest();
    if (oReq !== null) {
        if (connectionId !== 0) {
            oReq.open("GET", "/bret/hpc/index.php?id=" + connectionId + "&time=" + Math.random() * 1000, true);
            oReq.onreadystatechange = handler;
            oReq.onprogress = progress;
            oReq.send();
            return oReq;
        }
    } else {
        window.alert("AJAX (XMLHTTP) not supported.");
    }

    function progress() {
        progressFunc(oReq.responseText);
    }
}

function checkAction(param) {
    switch(param) {
        case 'nextSlide':
            nextSlide();
            break;
        case 'prevSlide':
            prevSlide();
            break;
        case 'play':
            animation.start();
            break;
        case 'pause':
            animation.stop();
            break;
    }
}